home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / ADB / SetLED / SetLED.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  7.9 KB  |  233 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SetLED.c
  3.     
  4.     Description:Sample program to demonstrate the use of the ADBOp call, including use
  5.                 of the completion routine under 68K, CFM68K, and PPC.
  6.             
  7.                 demonstrates a workaround for a bug with the CFM68K InterfaceLib glue
  8.                 code such that a call to ADBOp under CFM68K results in a bus error.
  9.                 This bug was identified with MacOS 8.1 running on different 68040 CPU's
  10.  
  11.     Author:        RK
  12.  
  13.     Copyright:     Copyright: © 1998-1999 by Apple Computer, Inc.
  14.                 all rights reserved.
  15.     
  16.     Disclaimer:    You may incorporate this sample code into your applications without
  17.                 restriction, though the sample code has been provided "AS IS" and the
  18.                 responsibility for its operation is 100% yours.  However, what you are
  19.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  20.                 after having made changes. If you're going to re-distribute the source,
  21.                 we require that you make it clear in the source that the code was
  22.                 descended from Apple Sample Code, but that you've made changes.
  23.     
  24.     Change History (most recent first):
  25.                 6/22/99    Updated for Metrowerks Codewarrior Pro 2.1(KG)
  26.                 4/7/98    Created(RK)
  27.  
  28. */
  29. #include <Types.h>
  30. #include <Events.h>
  31. #include <OSUtils.h>
  32. #include <DeskBus.h>
  33. #include <MixedMode.h>
  34.  
  35.  
  36. // keyboard ADB constants           
  37. #define kTalkCommand    8+4         
  38. #define kListenCommand  8           
  39. #define kLEDRegister    2       
  40.  
  41. #if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
  42. pascal long    GetA2( void )    ONEWORDINLINE(0x2E8A);
  43. #endif     //  TARGET_CPU_68K && !TARGET_RT_MAC_CFM
  44.  
  45. static long             gCompletionFlag;
  46. static ADBServiceRoutineUPP completionProc;                    
  47. static pascal void CompADBOp(void);
  48.  
  49. pascal OSErr MyADBOp(Ptr refCon, ADBServiceRoutineUPP compRout, 
  50.                             Ptr buffer, short commandNum);
  51.  
  52. // example completion routine for use with ADBOp
  53. pascal void CompADBOp(void)
  54. #if TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  55.     // Under, we can access global variables which is simpler
  56.     // than trying to write the glue code required so that 
  57.     // the completion routine is called with the registers
  58.     // set as per Inside Mac V-368
  59.     // set flag to indicate completion routine has completed
  60.     gCompletionFlag = 1;
  61. #else  // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  62.  
  63.     // under 68K, but not CFM-68K, all of the arguments are passed
  64.     // in registers so we use inline functions to access those
  65.     // arguments.  In this sample, the optional data
  66.     // buffer argument is interest since we want to set a boolean flag to 
  67.     // indicate that the completion routine has been executed.  A similar
  68.     // macro as that for GetA2 can be written to access the command buffer
  69.     // pointer in register A0
  70.     long     *completionFlagPtr;
  71.  
  72.     // set flag to indicate completion routine has run; A2 points to the flag
  73.     completionFlagPtr = (long*)GetA2(); 
  74.     *completionFlagPtr = 1;
  75. #endif  // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  76. } /* end of CompADBOp */
  77.  
  78. #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
  79. // The following code is implemented to fix a bug that exists with the 
  80. // 68K InterfaceLib glue code.  In order for the glue code to work, 
  81. // a pointer to an ADBOpBlock structure must be passed in register A0.
  82. // We define the global ADBOpBlock structure to support
  83. // the asynch ADBOp call
  84.  
  85. ADBOpBlock    gADBOpBlock;
  86. #endif     //  TARGET_CPU_68K && TARGET_RT_MAC_CFM
  87.  
  88. // Instead of making the ADBOp directly, call MyADBOp which makes 
  89. // the appropriate call depending on the target architecture.
  90. // For CFM68K, the ADBOpBlock structure is filled in and the
  91. // ADBGlue routine above is called. For regular 68K and PPC, the
  92. // ADBOp call is made straightaway.
  93.  
  94. pascal OSErr MyADBOp(
  95.      Ptr refCon,
  96.      ADBServiceRoutineUPP compRout,
  97.      Ptr buffer,
  98.      short commandNum)
  99. {
  100. #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
  101.     ADBOpBlock    adbOpBlock;
  102.  
  103.     adbOpBlock.dataBuffPtr = buffer;
  104.     adbOpBlock.opServiceRtPtr = compRout;
  105.     adbOpBlock.opDataAreaPtr = refCon;
  106.     
  107.     // Important Note: In this sample, we declare the adbOpBlock
  108.     // structure as a stack variable.  Normally it is bad practice
  109.     // to use a stack parameter for any asynchronous call.
  110.     // ADBOp makes a copy of the contents of the structure so the
  111.     // structure does not need to exist for the life of the 
  112.     // asynchronous call.
  113.  
  114.     // Note that the refCon value is placed into the ADBOpBlock
  115.     // structure for completeness.
  116.     // This program sample assumes that a completion routine, under
  117.     // CFM, will access the refCon and the data buffer as globals
  118.     // to the process, since under CFM, this is possible.
  119.     // Otherwise, more glue code is required so that when CFM calls
  120.     // the completion routine, the 68K registers will be set as
  121.     // per Inside Mac V-368.
  122.     
  123.     return (OSErr) CallUniversalProc((UniversalProcPtr)NGetTrapAddress(0xA07C, 0),
  124.             kRegisterBased |
  125.             RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
  126.             REGISTER_RESULT_LOCATION(kRegisterD0) |
  127.             REGISTER_ROUTINE_PARAMETER(1,
  128.                 kRegisterA0, SIZE_CODE(sizeof(&gADBOpBlock))) |
  129.             REGISTER_ROUTINE_PARAMETER(2,
  130.                 kRegisterD0, SIZE_CODE(sizeof(commandNum))),
  131.             &gADBOpBlock,
  132.             commandNum);
  133. #else  // TARGET_CPU_68K && TARGET_RT_MAC_CFM
  134.      return (ADBOp(refCon, compRout, buffer, commandNum));
  135. #endif  // TARGET_CPU_68K && TARGET_RT_MAC_CFM
  136. }
  137.  
  138. // set the leds to the given pattern }
  139. static void kb_SetMacNumLockLED( Boolean ledOn )
  140. {
  141.     OSErr               retCode;
  142.     ADBAddress          anADBadd;       // address of each device
  143.     Byte                regBuff[9];     // buffer for ADBOp commands
  144.     Byte                oldReg;
  145.     Byte                LEDPattern;
  146.     
  147.     if ( ledOn )
  148.         LEDPattern = 0x07;
  149.     else
  150.         LEDPattern = 0x00;
  151.     
  152.     // get an address for an ADB device - here we just talk to whatever keyboard
  153.     // is at ADB Address 2.  A more complete program might check the type of
  154.     // keyboard present to ensure that it has an LED present.
  155.     anADBadd = 2;
  156.     
  157.     regBuff[0] = (Byte)0; // initial data buffer length
  158.     regBuff[1] = 0;
  159.     regBuff[2] = 0;
  160.  
  161.     // initialize the completion flag so that we will know when the ADBOp call
  162.     // has completed.
  163.     gCompletionFlag = 0;
  164.     
  165.     retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  166.                                 kTalkCommand + kLEDRegister + 16 * anADBadd );
  167.     
  168.     if ( retCode != noErr )         // queue was full, try again
  169.     {
  170.         gCompletionFlag = 0;
  171.         retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  172.                                     kTalkCommand + kLEDRegister + 16 * anADBadd );
  173.         
  174.         if ( retCode != noErr )         // queue was still full, give up
  175.             return;
  176.     }
  177.     
  178.     // do nothing until completion routine has run
  179.     do
  180.     {
  181.     }
  182.     while ( ! gCompletionFlag );
  183.             
  184.     regBuff[0] = (Byte)2; // initial data buffer length
  185.     // extended keyboard has a word of data, LEDs are low 3 bits
  186.     oldReg = regBuff[2];
  187.     
  188.     // set the specified bits; note that a clear bit indicates a lit LED
  189.     // note that if LEDpattern is 7, then all three LED's will enable.
  190.     regBuff[2] = (oldReg & 255-7) | (7 - LEDPattern);
  191.  
  192.     // initialize the completion flag so that we will know when the ADBOp call
  193.     // has completed.
  194.     gCompletionFlag = 0;                        
  195.  
  196.     retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  197.                                 kListenCommand + kLEDRegister + 16 * anADBadd );
  198.  
  199.     if (retCode != noErr)
  200.         DebugStr("\p error on ADBOp for listen");
  201.     else
  202.     {
  203.             // do nothing until completion routine has run
  204.         do
  205.         {
  206.         }
  207.         while ( ! gCompletionFlag );
  208.     }
  209.  
  210. } /* end of kb_SetMacNumLockLED */
  211.  
  212.  
  213. void main (void)
  214. {
  215.     unsigned long    dummy;
  216.     short    i;
  217.  
  218.     completionProc = NewADBServiceRoutineProc( CompADBOp );
  219.  
  220.     i = 0;
  221.         // press the button to quit the test
  222.     while (!Button())
  223.     {
  224.         i++;
  225.         kb_SetMacNumLockLED(i % 2);
  226.         Delay(15, &dummy);
  227.     }
  228.  
  229.     if (completionProc != nil)
  230.         DisposeRoutineDescriptor( completionProc );
  231. }
  232.